#include "raytracer.h"
#include "bmp.h"

void RayTracer::startRayTracing()
{
    Vec xx,yy;   //屏幕上的坐标 原点在左上角 下方为x轴正方向 右方为y轴正方向
    for ( int i = 0 ; i < H ; i++ ){
        printf("%d%% ", i * 100 / H);
        for ( int j = 0 ; j < W ; j++ ){
            RGB color,rr;
            for (int x = -antiAliasing; x <= antiAliasing; x++){
                for (int y = -antiAliasing; y <= antiAliasing; y++){
                    double xx = i + 1.0 * x / (2 * antiAliasing + 1);
                    double yy = j + 1.0 * y / (2 * antiAliasing + 1);
                    rr = this->getColor(camera->emitLight(xx, yy), refDep);
                    color += rr;
                }
            }
//            Ray ray = camera->emitLight(i, j);
//            color = this->getColor(ray, 3);
            color.r /= sqr(2 * antiAliasing + 1);
            color.g /= sqr(2 * antiAliasing + 1);
            color.b /= sqr(2 * antiAliasing + 1);
            color.check();
            camera->setRGB(i, j, color);
        }
    }
}

RGB RayTracer::getColor(const Ray &ray, int reflectDepth)
{
    if (reflectDepth < 0) return RGB(0, 0, 0);
    int id;
    Vec N, P;
    Material material;
    int isCrash = scene->getCrashPoint(ray, id, N, P, material);
    if (!isCrash) return RGB(0, 0, 0);
    else {
        if (scene->object[id]->light) return RGB(1, 1, 1);
        RGB finalColor(0,0,0);

        this->calcReflect(finalColor ,ray, P, N, material, reflectDepth);
        this->calcDiffuse(finalColor, ray, P, N, material);

        return finalColor;
//        if (scene->object[id]->name != "plane"){
//            return finalColor;
//        }else {
//            int xx = int(P.x);
//            int yy = int(P.y);
//            if (P.x < 0) {
//                if ( ( xx + yy ) & 1 ) return RGB(0,0,0);
//                else return finalColor;
//            }else
//                if ( ! ( ( xx + yy ) & 1) ) return RGB(0,0,0);
//                else return finalColor;
//        }

    }
}



void RayTracer::calcDiffuse(RGB &finalColor, const Ray &ray, const Vec &P, const Vec &N, const Material &material)
{
    for(int i = 1; i <= scene->lightNum; i++){
        double Shade = scene->light[i]->checkShade(scene, P);
        //漫反射
        double tmp = N * ( ((PointLight*)scene->light[i])->O - P).normalize();
        if (tmp > zero) {
            tmp = tmp * material.diffuse;
            RGB a = material.color;
            finalColor = finalColor + (a * tmp * Shade);
        }
        //高光

        Vec R = ray.dir - N * ( 2.0 * ( ray.dir * N ) );
        double dot = R * (((PointLight*)scene->light[i])->O - P).normalize();
        if (dot > zero){
            finalColor = finalColor + ( RGB(1, 1, 1) * pow(dot, 20) * material.specular * Shade); // phong
        }
    }
}

void RayTracer::calcReflect(RGB &finalColor, const Ray &ray, const Vec &P, const Vec &N, const Material &material, int depth)
{
    Vec dir = ray.dir;
    if (depth == refDep){
        dir = (P - camera->cameraPosition).normalize(); // 景深矫正反射
    }
    Vec R = dir - N * ( 2.0 * ( dir * N ) );
    if (material.reflect > zero){
        finalColor = finalColor + getColor( Ray(P , R ), depth - 1 ) * material.reflect * material.color;
    }
}

void RayTracer::outputBmp()
{
    Bmp *bmp = new Bmp(H, W);
    for ( int i = 0 ; i < H ; i++ )
        for ( int j = 0 ; j < W ; j++ ){
            bmp->SetRGB(H - i - 1, j, camera->ima[i][j]);
        }
    bmp->Output("a.bmp");
}
